/* Copyright (c) 2021-2025 Qualcomm Technologies International, Ltd. */
/* %%version */

#include "gatt_vcs_client.h"

#include "vcp.h"
#include "vcp_private.h"
#include "vcp_destroy.h"
#include "vcp_common.h"
#include "vcp_debug.h"

/*******************************STATIC_FUNCTIONS_START***********************************************/
#ifndef EXCLUDE_CSR_BT_VOCS_CLIENT_MODULE
static CsrBool vocsSetDeviceData(CsrCmnListElm_t *element, void *value)
{
    vcpVocsServiceQueueElement *incElement = (vcpVocsServiceQueueElement *)element;
    GattVocsClientTerminateCfm *message = (GattVocsClientTerminateCfm *)value;

    if (incElement && incElement->service_handle == 0x00)
    {
         memcpy(&incElement->device_data, &message->deviceData, sizeof(GattVocsClientDeviceData));
         return TRUE;
    }
    return FALSE;

}
#endif /* !EXCLUDE_CSR_BT_VOCS_CLIENT_MODULE */

#ifndef EXCLUDE_CSR_BT_AICS_CLIENT_MODULE
static CsrBool aicsSetDeviceData(CsrCmnListElm_t *element, void *value)
{
    vcpAicsServiceQueueElement *incElement = (vcpAicsServiceQueueElement *)element;
    GattAicsClientTerminateCfm *message = (GattAicsClientTerminateCfm *)value;

    if (incElement && incElement->service_handle == 0x00)
    {
         memcpy(&incElement->device_data, &message->deviceData, sizeof(GattAicsClientDeviceData));
         return TRUE;
    }
    return FALSE;

}

static void terminateAics(CsrCmnListElm_t *element, void *value)
{
    vcpAicsServiceQueueElement *incElement = (vcpAicsServiceQueueElement *)element;

    if (incElement)
    {
        GattAicsClientTerminateReq(incElement->service_handle);
    }

    CSR_UNUSED(value);
}
#endif /* !EXCLUDE_CSR_BT_AICS_CLIENT_MODULE */

static void terminateIncService(CsrCmnListElm_t *elem, void *value)
{
    vcpIncOptService incService = *(vcpIncOptService*)value;

    if (incService == VCP_INCLUDE_VOCS)
    {
        vcpVocsServiceQueueElement *incElement = (vcpVocsServiceQueueElement*)elem;

        if (incElement)
        {
            GattVocsClientTerminateReq(incElement->service_handle);
        }
    }
    else if (incService == VCP_INCLUDE_AICS)
    {
        vcpAicsServiceQueueElement *incElement = (vcpAicsServiceQueueElement*)elem;

        if (incElement)
        {
             GattAicsClientTerminateReq(incElement->service_handle);
        }
    }
}

static void incServiceCfm (CsrCmnListElm_t *element, void *value)
{
    VCP *vcp_inst = NULL;
    ProfileHandleListElm_t *elem = NULL;
    vcp_main_inst *vcp_main = vcpGetMainInstance();
    vcpIncOptService incService = *(vcpIncOptService *)value;

    if (incService == VCP_INCLUDE_VOCS)
    {
        vcpVocsServiceQueueElement *vocsIncElement = (vcpVocsServiceQueueElement *)element;

        if (vocsIncElement)
        {
            elem = VCP_FIND_PROFILE_HANDLE_BY_VOCS_SERVICE_HANDLE(vcp_main->profile_handle_list,
                vocsIncElement->service_handle);

            if (elem)
            {
                vcp_inst = FIND_VCP_INST_BY_PROFILE_HANDLE(elem->profile_handle);
            }

            if (vcp_inst)
            {
                MAKE_VCP_MESSAGE(VcpVocsTerminateCfm);

                message->id = VCP_VOCS_TERMINATE_CFM;
                message->prflHndl = vcp_inst->vcp_srvc_hdl;
                message->vocsSizeValue = vcp_inst->vocs_counter;
                message->startHandle = vocsIncElement->device_data.startHandle;
                message->endHandle = vocsIncElement->device_data.endHandle;

                memcpy(&message->vocsValue, &vocsIncElement->device_data, sizeof(GattVocsClientDeviceData));
                
                if(vocsIncElement)
                {
                    message->moreToCome = TRUE;
                }
                else
                {
                    message->moreToCome = FALSE;
                }

                VcpMessageSend(vcp_inst->app_task, message);
            }
            else
            {
                 VCP_DEBUG("Invalid VCP prfoile handle");
            }
        }
    }
    else if (incService == VCP_INCLUDE_AICS)
    {
        vcpAicsServiceQueueElement *aicsIncElement = (vcpAicsServiceQueueElement *)element;

        if (aicsIncElement)
        {
            elem = VCP_FIND_PROFILE_HANDLE_BY_AICS_SERVICE_HANDLE(vcp_main->profile_handle_list,
                aicsIncElement->service_handle);
        
            if (elem)
            {
                vcp_inst = FIND_VCP_INST_BY_PROFILE_HANDLE(elem->profile_handle);
            }
        
            if (vcp_inst)
            {
                MAKE_VCP_MESSAGE(VcpAicsTerminateCfm);

                message->id = VCP_AICS_TERMINATE_CFM;
                message->prflHndl = vcp_inst->vcp_srvc_hdl;
                message->aicsSizeValue = vcp_inst->aics_counter;
                message->startHandle = aicsIncElement->device_data.startHandle;
                message->endHandle = aicsIncElement->device_data.endHandle;

                memcpy(&message->aicsValue, &aicsIncElement->device_data, sizeof(GattVocsClientDeviceData));
                
                if(aicsIncElement)
                {
                    message->moreToCome = TRUE;
                }
                else
                {
                    message->moreToCome = FALSE;
                }

                VcpMessageSend(vcp_inst->app_task, message);
            }
            else
            {
                 VCP_DEBUG("Invalid VCP prfoile handle");
            }
        }
    }
}
/********************************STATIC_FUNCTIONS_END**********************************************/

/**************************************************************************************************/

void vcpSendDestroyCfm(VCP * vcp_inst, VcpStatus status)
{
    MAKE_VCP_MESSAGE(VcpDestroyCfm);

    message->id = VCP_DESTROY_CFM;
    message->status = status;
    message->prflHndl = vcp_inst->vcp_srvc_hdl;

    VcpMessageSend(vcp_inst->app_task, message);
}

/******************************************************************************/
void VcpDestroyReq(VcpProfileHandle profileHandle)
{
    VCP * vcp_inst = ServiceHandleGetInstanceData((ServiceHandle) profileHandle);

    if (vcp_inst)
    {
        /* Send confirmation message with status in progress */
        vcpSendDestroyCfm(vcp_inst, VCP_STATUS_IN_PROGRESS);

        /* Terminate VCS Client */
        GattVcsClientTerminateReq(vcp_inst->vcs_srvc_hdl);
    }
    else
    {
        VCP_DEBUG("Invalid profile handle\n");
    }
}

/******************************************************************************/
void vcpSendVcsTerminateCfm(VCP *vcp_inst,
                            VcpStatus status,
                            GattVcsClientDeviceData handles)
{
    MAKE_VCP_MESSAGE(VcpVcsTerminateCfm);

    message->id = VCP_VCS_TERMINATE_CFM;
    message->status = status;
    message->prflHndl = vcp_inst->vcp_srvc_hdl;

    memcpy(&(message->vcsHandle), &handles, sizeof(GattVcsClientDeviceData));

    VcpMessageSend(vcp_inst->app_task, message);
}

#ifndef EXCLUDE_CSR_BT_AICS_CLIENT_MODULE
/****************************************************************************/
void vcpHandleAicsClientTerminateResp(VCP *vcp_inst,
                                      const GattAicsClientTerminateCfm *message)
{
    if (message->status == GATT_AICS_CLIENT_STATUS_SUCCESS)
    {
        /* A AICS Client instance has been terminated successfully. */
        vcp_inst->aics_counter -= 1;

        CsrCmnListSearch(&vcp_inst->vocs_service_queue, aicsSetDeviceData, (void*)message);

        if (!vcp_inst->aics_counter)
        {
            /* We can destroy all the list we have in the profile context */
            vcpDestroyProfileInst(vcp_inst);
        }
    }
    else
    {
        vcpSendDestroyCfm(vcp_inst, VCP_STATUS_FAILED);
    }
}
#endif

#ifndef EXCLUDE_CSR_BT_VOCS_CLIENT_MODULE
/****************************************************************************/
void vcpHandleVocsClientTerminateResp(VCP *vcp_inst,
                                      const GattVocsClientTerminateCfm *message)
{
    if (message->status == GATT_VOCS_CLIENT_STATUS_SUCCESS)
    {
        /* A VOCS Client instance has been terminated successfully. */
        vcp_inst->vocs_counter -= 1;

        CsrCmnListSearch(&vcp_inst->vocs_service_queue, vocsSetDeviceData,(void*) message);

        if (!vcp_inst->vocs_counter)
        {
            /* All the VOCS Client instances are terminated */
            if (vcp_inst->aics_counter)
            {
                CsrCmnListIterate(&vcp_inst->aics_service_queue, terminateAics, NULL);
            }
            else
            {
                /* There are no instances of AICS to terminate */
                vcpDestroyProfileInst(vcp_inst);
            }
        }
    }
    else
    {
        vcpSendDestroyCfm(vcp_inst, VCP_STATUS_FAILED);
    }
}
#endif


/****************************************************************************/
void vcpHandleVcsClientTerminateResp(VCP *vcp_inst,
                                     const GattVcsClientTerminateCfm *message)
{
    if (message->status == GATT_VCS_CLIENT_STATUS_SUCCESS)
    {
         vcpIncOptService incService = VCP_INCLUDE_VOCS;

         /* VCS Client has been terminated successfully. */
        /* Send the vcs characteristic handles to the application */
        vcpSendVcsTerminateCfm(vcp_inst,
                               VCP_STATUS_SUCCESS,
                               message->deviceData);

        /* If there are VOCS Client instances initialised, we have to terminate them */
        if (vcp_inst->vocs_counter)
        {
            CsrCmnListIterate(&vcp_inst->vocs_service_queue, terminateIncService, &incService);
        }
        else if (vcp_inst->aics_counter)
        {
            /* If there are no instances of VOCS, but there are AICS instances, we need to
             * terminate them too.
             */
            incService = VCP_INCLUDE_AICS;
            CsrCmnListIterate(&vcp_inst->aics_service_queue, terminateIncService , &incService);
        }
        else
        {
            /* There are no instances of VOCS or AICS */
            vcpDestroyProfileInst(vcp_inst);
        }
    }
    else
    {
        vcpSendDestroyCfm(vcp_inst, VCP_STATUS_FAILED);
    }
}

/****************************************************************************/

void vcpSendIncludedServicesTerminateCfm(VCP *vcp_inst, VcpStatus status)
{
    vcpIncOptService incService = VCP_INCLUDE_VOCS;

    /* Update the count for VOCS/AICS instance */
    vcp_inst->vocs_counter = vcp_inst->vocs_service_queue.count;
    vcp_inst->aics_counter = vcp_inst->aics_service_queue.count;

    CsrCmnListIterateAllowRemove((CsrCmnList_t*)&vcp_inst->vocs_service_queue, (CsrCmnListIterateAllowRemoveFunc_t)incServiceCfm, (void *)&incService);

    incService = VCP_INCLUDE_AICS;
    CsrCmnListIterateAllowRemove((CsrCmnList_t*)&vcp_inst->aics_service_queue, (CsrCmnListIterateAllowRemoveFunc_t)incServiceCfm, (void *)&incService);
    CSR_UNUSED(status);
}

/****************************************************************************/
void vcpDestroyProfileInst(VCP *vcp_inst)
{
    CsrBool res = FALSE;
    AppTask app_task = vcp_inst->app_task;
    vcp_main_inst* vcp_main = vcpGetMainInstance();
    MAKE_VCP_MESSAGE(VcpDestroyCfm);

    /* Send the confirmation message */
    message->id = VCP_DESTROY_CFM;
    message->prflHndl = vcp_inst->vcp_srvc_hdl;

    /* Send the VOCS and AICS characteristic handles to the application */
    vcpSendIncludedServicesTerminateCfm(vcp_inst, VCP_STATUS_SUCCESS);
    CsrBtGattUnregisterReqSend(vcp_inst->gattId);

   if (vcp_main)
   {
       VCP_REMOVE_SERVICE_HANDLE(vcp_main->profile_handle_list, vcp_inst->vcp_srvc_hdl);
   }

    /* Clear pending messages
    MessageFlushTask((Task)&vcp_inst->lib_task); */

    /* Free the profile instance memory */
    res = ServiceHandleFreeInstanceData((ServiceHandle) (vcp_inst->vcp_srvc_hdl));

    if (res)
    {
        message->status = VCP_STATUS_SUCCESS;
    }
    else
    {
        message->status = VCP_STATUS_FAILED;
    }

    VcpMessageSend(app_task, message);
}
